package cn.com.xy.sms.sdk.service.number;

import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import org.json.JSONArray;
import org.json.JSONObject;

import android.util.Pair;
import cn.com.xy.sms.sdk.Iservice.XyCallBack;
import cn.com.xy.sms.sdk.constant.Constant;
import cn.com.xy.sms.sdk.db.entity.NumberInfo;
import cn.com.xy.sms.sdk.db.entity.NumberInfoManager;
import cn.com.xy.sms.sdk.db.entity.SysParamEntityManager;
import cn.com.xy.sms.sdk.log.LogManager;
import cn.com.xy.sms.sdk.net.NetUtil;
import cn.com.xy.sms.sdk.number.ParseNumberCache;
import cn.com.xy.sms.sdk.util.CallBackState;
import cn.com.xy.sms.sdk.util.StringUtils;
import cn.com.xy.sms.sdk.util.XyUtil;
import cn.com.xy.sms.util.SdkCallBack;

/* SDK-428 huangzhiqiang 20160615 start */
public class ParseNumberService {

    /**
     * 联网查询号码信息
     * 
     * @param queryNumMap 号码对应版本号Map
     * @param extend 扩展参数:
     *                  "lat":纬度(double类型)(如果传递了该扩展参数，固话自动加区号将使用该纬度，必须和经度一起传递)
     *                  "lng":经度(double类型)(如果传递了该扩展参数，固话自动加区号将使用该经度，必须和纬度一起传递)
     * @param callBack 
     *            index0(状态):
     *                CallBackState.HAS_DATA:当前线程或新线程，成功获取号码数据
     *                CallBackState.NO_DATA:当前线程或新线程，暂无号码数据
     *                CallBackState.ERROR:存在异常，获取号码数据失败
     *            index1:Set<String>类型 号码集合(可能为null)
     *            index2:(index0 == CallBackState.HAS_DATA):JSONArray类型 号码数据集合,例:
     *                    [
     *                     {"pubnum":"10086","numtype":1,"name":"中国移动","area":"广东","version":"201606061325", "logo":"af3647264b2c71fd6c03cf9f5e708bdb.png"},
     *                     {"pubnum":"13890870000","numtype":2,"tag":"骚扰电话","amount":100,"version":"201606061325"},
     *                     {"pubnum":"13890870000","version":"201606061325"},
     *                     {"pubnum":"13890870000","extMsg":{"numtype":"电话类型"}}
     *                    ]
     *                    (index0 == CallBackState.NO_DATA):"no data"
     *                    (index0 == CallBackState.ERROR):String类型 异常信息
     */
    public static void parseByService(Map<String, String> queryNumMap, Map<String, String> extend,
            final XyCallBack callBack) {
        if (queryNumMap == null || queryNumMap.isEmpty()) {
            XyUtil.doXycallBackResult(callBack, CallBackState.ERROR, null, "no number");
            return;
        }

        final Set<String> queryNums = queryNumMap == null ? null : queryNumMap.keySet();
        final String reqeustContent = createReqeustContent(queryNumMap, extend);
        if (StringUtils.isNull(reqeustContent)) {
            XyUtil.doXycallBackResult(callBack, CallBackState.ERROR, queryNums, "reqeustContent == null");
            return;
        }

        SdkCallBack netSdkCallBack = new SdkCallBack() {

            @Override
            public void execute(Object... obj) {
                try {
                    int callBackState = (Integer) obj[0];
                    Object result = obj[1];
                    if (callBackState != CallBackState.REQUEST_SUCCESS) {
                        XyUtil.doXycallBackResult(callBack, callBackState, queryNums, result);
                        return;
                    }

                    JSONArray resultArr = new JSONArray((String) result);
                    JSONArray effectiveResultArr = handleResultAndReturnEffectiveData(resultArr);

                    if (effectiveResultArr.length() > 0) {
                        XyUtil.doXycallBackResult(callBack, CallBackState.HAS_DATA, queryNums, effectiveResultArr);
                    } else {
                        XyUtil.doXycallBackResult(callBack, CallBackState.NO_DATA, queryNums, "no data");
                    }
                } catch (Throwable e) {
                    LogManager.e(Constant.TAG, "ParseNumberService parseByService execute error:", e);
                    XyUtil.doXycallBackResult(callBack, CallBackState.ERROR, queryNums, e.getMessage());
                }
            }
        };
        try {
            NetUtil.executeServiceHttpRequest(NetUtil.REQ_QUERY_NUM, reqeustContent, extend, netSdkCallBack);
        } catch (Throwable e) {
            LogManager.e(Constant.TAG, "ParseNumberService parseByService error:", e);
            XyUtil.doXycallBackResult(callBack, CallBackState.ERROR, queryNums, e.getMessage());
        }
    }

    /**
     * 号码识别请求参数
     * 
     * @param queryNumMap 号码对应版本号map
     * @param extend 扩展参数
     * @return 例:{"lat":31.974449,"lng":118.75813,"items":[{"pubnum":"10086","version":"121231"},{"pubnum":"10010"}]}
     */
    private static String createReqeustContent(Map<String, String> queryNumMap, Map<String, String> extend) {
        if (queryNumMap == null || queryNumMap.isEmpty()) {
            return null;
        }

        try {
            JSONObject reqeustContent = new JSONObject();
            reqeustContent.put("items", createNumberItemsReqeustContent(queryNumMap));

            Pair<Double, Double> latLngPair = getLatLngPair(extend);
            if (latLngPair != null && latLngPair.first != 0D && latLngPair.second != 0D) {
                reqeustContent.put(Constant.LOACTION_LATITUDE, latLngPair.first);
                reqeustContent.put(Constant.LOACTION_LONGITUDE, latLngPair.second);
            }
            return reqeustContent.toString();
        } catch (Throwable e) {
            LogManager.e(Constant.TAG, "ParseNumberService createReqeustContent error:", e);
        }
        return null;
    }

    private static JSONArray createNumberItemsReqeustContent(Map<String, String> queryNumMap) {
        JSONArray numArr = new JSONArray();
        Set<Entry<String, String>> entrySet = queryNumMap.entrySet();
        for (Entry<String, String> entry : entrySet) {
            String num = entry.getKey();
            if (StringUtils.isNull(num)) {
                continue;
            }
            try {
                JSONObject numInfoObj = new JSONObject();
                numInfoObj.put(NumberInfo.NUM_KEY, num);
                String version = entry.getValue();
                if (!StringUtils.isNull(version)) {
                    numInfoObj.put(NumberInfo.VERSION_KEY, version);
                }
                numArr.put(numInfoObj);
            } catch (Throwable e) {
                LogManager.e(Constant.TAG,
                        "ParseNumberService createNumberItemsReqeustContent error:", e);
            }
        }
        return numArr;
    }

    private static Pair<Double, Double> getLatLngPair(Map<String, String> extend) {
        Pair<Double, Double> latLngPair = createLatLngPairByExtend(extend);
        if (latLngPair != null) {
            saveExtendLatLngToDBAndRemoveAreaCodeInfo(latLngPair);
        } else {
            latLngPair = createLatLngPairBySysParam();
        }
        return latLngPair;
    }

    private static void saveExtendLatLngToDBAndRemoveAreaCodeInfo(Pair<Double, Double> latLngPair) {
        try {
            // 如果扩展参数存在经纬度信息，更新到数据库
            XyUtil.setLoactionInfo(latLngPair.first, latLngPair.second);
            // 清空旧区号，经纬度变化以后需要重新获取区号
            XyUtil.removeAreaCodeInfo();
        } catch (Throwable e) {
            LogManager.e(Constant.TAG,
                    "ParseNumberService saveExtendLatLngToDBAndRemoveAreaCodeInfo error:", e);
        }
    }

    private static Pair<Double, Double> createLatLngPairByExtend(Map<String, String> extend) {
        if (!extendHasLatLngInfo(extend)) {
            return null;
        }
        try {
            Double latitude = Double.parseDouble(extend.get(Constant.LOACTION_LATITUDE));
            Double longitude = Double.parseDouble(extend.get(Constant.LOACTION_LONGITUDE));
            return new Pair<Double, Double>(latitude, longitude);
        } catch (Throwable e) {
            LogManager.e(Constant.TAG, "ParseNumberService createLatLngPairByExtend error:", e);
        }
        return null;
    }

    public static boolean extendHasLatLngInfo(Map<String, String> extend) {
        return extend != null && !StringUtils.isNull(extend.get(Constant.LOACTION_LATITUDE))
                && !StringUtils.isNull(extend.get(Constant.LOACTION_LONGITUDE));
    }

    private static Pair<Double, Double> createLatLngPairBySysParam() {
        try {
            JSONObject loaction = XyUtil.getLoaction();
            if (loaction != null) {
                return new Pair<Double, Double>(loaction.optDouble(Constant.LOACTION_LATITUDE, 0D), loaction.optDouble(
                        Constant.LOACTION_LONGITUDE, 0D));
            }
        } catch (Throwable e) {
            LogManager.e(Constant.TAG, "ParseNumberService createLatLngPairBySysParam error:", e);
        }
        return null;
    }

    /**
     * 处理返回结果，将所有号码识别结果入库及返回有效的识别结果
     * 
     * @param resultArr 号码识别结果集合
     * @return
     */
    private static JSONArray handleResultAndReturnEffectiveData(JSONArray resultArr) {
        if (resultArr == null || resultArr.length() == 0) {
            return null;
        }
        JSONArray effectiveResultArr = new JSONArray();
        long lastQueryTime = System.currentTimeMillis();
        int dataLength = resultArr.length();
        for (int i = 0; i < dataLength; i++) {
            try {
                JSONObject numInfo = resultArr.getJSONObject(i);
                String num = numInfo.optString(NumberInfo.NUM_KEY);
                /* IMOO-14 likuangkuang 20161018 start */
                // only effective data will insertOrUpdate
                if (StringUtils.isNull(num) || !NumberInfoManager.isEffectiveData(numInfo)) {
                    continue;
                }
                /* IMOO-14 likuangkuang 20161018 start */
                
                LogManager.i(Constant.TAG, "ParseNumberService net numinfo:" + numInfo);
                // 没有新数据时只需更新最后查询时间
                if (notHaveNewData(numInfo)) {
                    NumberInfoManager.updateLastQueryTime(num, System.currentTimeMillis());
                    continue;
                }

                saveAreaCode(numInfo);

                String version = numInfo.optString(NumberInfo.VERSION_KEY);
                long id = NumberInfoManager.insertOrUpdate(num, numInfo, version, lastQueryTime);
                if (id > 0) {
                    ParseNumberCache.addCache(num, numInfo);
                    ParseNumberCache.removeInvalidNum(num);
                    effectiveResultArr.put(numInfo);
                }
            } catch (Throwable e) {
                LogManager.e(Constant.TAG,
                        "ParseNumberService handleResultAndReturnEffectiveData error:", e);
            }
        }
        return effectiveResultArr;
    }

    /**
     * 保存返回报文中的固话区号
     * 
     * @param numInfo
     */
    private static void saveAreaCode(JSONObject numInfo) {
        if (numInfo == null) {
            return;
        }
        String areaCode = numInfo.optString(Constant.AREA_CODE);
        if (StringUtils.isNull(areaCode)) {
            return;
        }
        String currentAreaCode = SysParamEntityManager.getStringParam(Constant.getContext(), Constant.AREA_CODE);
        if (!areaCode.equals(currentAreaCode)) {
            SysParamEntityManager.setParam(Constant.AREA_CODE, areaCode);
        }
    }

    private static boolean notHaveNewData(JSONObject numInfoObj) {
        // 接口只返回号码和版本号时代表没有新数据
        return numInfoObj.length() == 2 && numInfoObj.has(NumberInfo.NUM_KEY) && numInfoObj.has(NumberInfo.VERSION_KEY);
    }
}
/* SDK-428 huangzhiqiang 20160615 end */
